package mnet

/*
 * session which can execute all tcp events in a single goroutine.
 */

import (
	"sync"
	"sync/atomic"
)

// net event type.
const (
	evtConnectType    uint16 = 0
	evtDisconnectType uint16 = 1
	evtDataType       uint16 = 2
)

// net event struct
type netEvent struct {
	evtType uint16         // event type
	sink    ISink          // sink
	msg     []byte         // data
	session *SingleSession // single session
}

// global netEvent pool
var evtPool = sync.Pool{
	New: func() interface{} {
		return new(netEvent)
	},
}

// wrap sink SingleSession, can only create by NewSingleSession() function
// which must initialize with ISink interface.
type SingleSession struct {
	conn  IConnection // net connection.
	state int32       // state:1,closed:0.
	sink  ISink       // user sink
}

// receiving data callback.
func (s *SingleSession) OnRecv(msg []byte) {
	evt := evtPool.Get().(*netEvent)
	evt.evtType = evtDataType
	evt.sink = s.sink
	evt.msg = make([]byte, len(msg))
	copy(evt.msg, msg)
	gNetInstance.push(evt)
}

// Establish connection callback
func (s *SingleSession) OnEstablish() {
	atomic.StoreInt32(&s.state, gOpenFlag)

	evt := evtPool.Get().(*netEvent)
	evt.evtType = evtConnectType
	evt.sink = s.sink
	evt.session = s
	gNetInstance.push(evt)
}

// Terminate connection callback
func (s *SingleSession) OnTerminate() {
	atomic.StoreInt32(&s.state, gClosedFlag)

	evt := evtPool.Get().(*netEvent)
	evt.evtType = evtDisconnectType
	evt.sink = s.sink
	evt.session = s
	gNetInstance.push(evt)
}

// Set IConnection
func (s *SingleSession) SetConnection(conn IConnection) {
	s.conn = conn
}

// Whether it is connected.
func (s *SingleSession) IsConnected() bool {
	return atomic.LoadInt32(&s.state) == gOpenFlag
}

// Send send msg
func (s *SingleSession) Send(msg []byte) {
	if s.IsConnected() {
		s.conn.SendMsg(msg)
	}
}
func (s *SingleSession) SendMsg(msgId uint16, msg []byte) {
	s.Send(gMyMsgCodec.BuildProto(msgId, msg))
}

// close connection.
func (s *SingleSession) Close() {
	if s.IsConnected() {
		s.conn.Close()
	}
}
